# -*- coding: UTF-8 -*-
# cython: language_level=3
# @Author: winter
# @Contact: winter@stu2016.jnu.edu.cn
# @Desc: 曲奇云盘上传文件或文件夹
#        测试使用ChromeDriver版本：104.0.5112.79
#        测试使用selenium版本：4.4.0

from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium import webdriver
from functools import wraps
from time import sleep
import os


def need_login(func, auto_login=True):
    @wraps(func)
    def wrapTheFunction(self, *args, **kwargs):
        if not self.login_success(auto_login=auto_login):
            print("登录失败！")
            return
        return func(self, *args, **kwargs)
    return wrapTheFunction

class QUQI:
    def __init__(self, chromedrive: str, action_sleep_long: float = 3.0, action_sleep_short: float = 1.0, name: str = None, pwd: str = None):
        options = webdriver.ChromeOptions()
        options.add_argument('--headless')
        options.add_argument('--no-sandbox')
        self.driver = webdriver.Chrome(chromedrive, options=options)
        self.driver.execute_cdp_cmd('Network.setUserAgentOverride', {
            "userAgent": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2226.0 Safari/537.36",
        })
        self.action_sleep_long = action_sleep_long
        self.action_sleep_short = action_sleep_short
        self.name = name
        self.pwd = pwd
        if name and pwd:
            self.login(name, pwd)
    
    def __test_login_success(self):
        return "会员中心" in self.driver.find_element(by=By.TAG_NAME, value='body').text
    
    def login_success(self, auto_login=False):
        res = self.__test_login_success()
        left_times = 3
        while auto_login and (not res) and (left_times > 0):
            if self.name and self.pwd:
                left_times -= 1
                self.login(self.name, self.pwd)
                res = self.__test_login_success()
            else:
                print("账号或密码不存在！")
                break
        return res


    def login(self, name: str, pwd: str):
        """ 登录
        """
        print("开始登录...")
        self.name = name
        self.pwd = pwd
        self.driver.get('https://quqi.com/p/login.html')
        loginRoot = self.driver.find_element(by=By.ID, value='phone-password-login-form')
        loginidInput = loginRoot.find_element(by=By.ID, value='password-login-phone-text')
        loginpassword = loginRoot.find_element(by=By.ID, value='password-login-word-text')
        loginbutton = loginRoot.find_element(by=By.ID, value='btn-signup')
        loginidInput.send_keys(name)
        loginpassword.send_keys(pwd)
        sleep(self.action_sleep_short)
        loginbutton.click()
        sleep(self.action_sleep_long)
        if self.__test_login_success():
            print("登录失败！")
        else:
            print("登录成功！")
    

    def close(self):
        self.driver.close()


    @need_login
    def upload_file(self, file_path: str, aim_dir: str = "/"):
        """ 上传文件
        """
        if not os.path.isfile(file_path):
            print(file_path, 'is not a file !')
            return 
        file_path = os.path.abspath(file_path)
        print("上传文件“{}”到“{}”文件夹...".format(file_path, aim_dir))
        self.change_dir(aim_dir)
        uploaddir = self.driver.find_elements(by=By.NAME, value='files')
        uploaddir[0].send_keys(file_path)
        sleep(self.action_sleep_long)
    

    @need_login
    def upload_dir(self, dir_path: str, aim_dir: str = "/"):
        """ 上传文件夹

        如果目标文件夹不存在将会创建
        """
        if not os.path.isdir(dir_path):
            print(dir_path, 'is not a path !')
            return 
        self.change_dir(aim_dir)
        for root, dirs, files in os.walk(dir_path):
            # 新建文件夹
            for dir_single in dirs:
                self.create_dir(os.path.join(aim_dir, dir_single))
            # 上传文件
            for file_single in files:
                self.upload_file(os.path.join(root, file_single), aim_dir)


    @need_login
    def goto_index(self):
        """ 前往网盘首页
        """
        self.driver.get('https://quqi.com/')
        sleep(self.action_sleep_long)
    

    @need_login
    def change_dir(self, dir_absolute_path: str, need_create: bool = True):
        """ 更改当前目录
        """
        self.goto_index()
        for dir_name in dir_absolute_path.split(sep=os.sep):
            if dir_name.strip() == "":
                continue
            self.__change_dir_single(dir_name, need_create)
    

    def __has_dir_single(self, dir_name: str):
        res = False
        for ii in self.driver.find_elements(by=By.CLASS_NAME, value='webix_column'):
            if ii.get_attribute("column") != '2':
                continue
            for i in ii.find_elements(by=By.CLASS_NAME, value='webix_cell'):
                i_span = i.find_elements(by=By.TAG_NAME, value='span')
                if ("icon-folder" in i_span[0].get_attribute('class')) and (dir_name == i_span[1].text.strip()):
                    res = True
                    break
            break
        return res
    

    def __change_dir_single(self, dir_name: str, need_create: bool= False):
        new_btn = None
        for ii in self.driver.find_elements(by=By.CLASS_NAME, value='webix_column'):
            if ii.get_attribute("column") != '2':
                continue
            for i in ii.find_elements(by=By.CLASS_NAME, value='webix_cell'):
                i_span = i.find_elements(by=By.TAG_NAME, value='span')
                if ("icon-folder" in i_span[0].get_attribute('class')) and (dir_name == i_span[1].text.strip()):
                    new_btn = i
                    break
            break
        if new_btn:
            ActionChains(self.driver).double_click(new_btn).perform()
            sleep(self.action_sleep_short)
        else:
            print("当前目录下，“", dir_name, "”文件夹不存在！")
            if need_create:
                print("开始创建“", dir_name, "”文件夹...")
                self.__create_dir_single(dir_name)
                self.__change_dir_single(dir_name)


    @need_login
    def create_dir(self, dir_absolute_path: str):
        """ 创建目录
        """
        self.goto_index()
        for dir_name in dir_absolute_path.split(sep=os.sep):
            if dir_name.strip() == "":
                continue
            if not self.__has_dir_single(dir_name):
                self.__create_dir_single(dir_name)
            self.__change_dir_single(dir_name)
        self.goto_index()


    def __create_dir_single(self, dir_name: str):
        # 点击新建
        new_btn = None
        for i in self.driver.find_elements(by=By.CLASS_NAME, value='webix_list_item'):
            if "新建" in i.text:
                new_btn = i
                break
        new_btn.click()
        sleep(self.action_sleep_short)
        # 点击新建文件夹
        new_btn = None
        for i in self.driver.find_elements(by=By.CLASS_NAME, value='webix_list_item'):
            if "文件夹" in i.text:
                new_btn = i
                break
        new_btn.click()
        sleep(self.action_sleep_short)
        # 输入文件夹名字
        new_btn = None
        for i in self.driver.find_elements(by=By.TAG_NAME, value='input'):
            if "新建文件夹" in i.get_attribute('placeholder'):
                new_btn = i
                break
        new_btn.send_keys(dir_name)
        sleep(self.action_sleep_short)
        # 提交
        new_btn = None
        for ii in self.driver.find_elements(by=By.CLASS_NAME, value='webix_window'):
            if ii.get_attribute("view_id") != 'new_dir_view':
                continue
            for i in ii.find_elements(by=By.TAG_NAME, value='button'):
                if "确定" in i.text:
                    new_btn = i
                    break
            break
        new_btn.click()
        sleep(self.action_sleep_long)
    

    @need_login
    def upload(self, path: str, aim_path: str):
        """ 上传文件或文件夹

        自动根据源路径判断上传方法，如果目标文件夹不存在，将会创建目标文件夹。
        """
        if os.path.isdir(path):
            self.upload_dir(path, aim_path)
        elif os.path.isfile(path):
            self.upload_file(path, aim_path)
        else:
            print("未知的类型！")
    

    def __enter__(self):
        return self


    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()


if __name__ == "__main__":

    # 例1：上下文管理器便捷使用
    with QUQI('chromedrive_path', name='用户名', pwd='密码') as q:
        q.upload('上传文件夹路径', '目标文件夹路径')

    # 例2：自行调用对象方法
    q = QUQI('chromedrive_path')
    q.login(
        name='用户名',
        pwd='密码'
    )
    q.upload_dir(
        '上传文件夹路径',
        '目标文件夹路径'
    )
    q.close()